package com.lxxie;

import io.reactivex.Single;
import jodd.util.concurrent.ThreadFactoryBuilder;
import org.redisson.Redisson;
import org.redisson.api.*;
import reactor.core.publisher.Mono;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created by xielx on 20/9/16 15:30
 */
public class RedisLock {
        private static RedissonClient redisson;


        static {
                redisson = Redisson.create();
        }

        public void normalLock() throws InterruptedException {
                RLock lock = redisson.getLock("myLock");
                // traditional lock method
                //lock.lock();
                // or acquire lock and automatically unlock it after 10 seconds
                lock.lock(10, TimeUnit.SECONDS);
                // or wait for lock aquisition up to 100 seconds
                // and automatically unlock it after 10 seconds
                boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
                if (res) {
                        try {
                                //TODO do some thing
                        } finally {
                                lock.unlock();
                        }
                }

        }

        public static void main(String[] args) {
                ExecutorService pool = Executors.newFixedThreadPool(10,new ThreadFactoryBuilder().setNameFormat("抢锁-%d").get());
                CountDownLatch ct = new CountDownLatch(10);
                for (int i = 0; i < 10; i++) {
                        pool.submit(()->{
                                RLock lock = redisson.getLock("myLock");
                                try {
                                        boolean res = lock.tryLock(100, 10, TimeUnit.SECONDS);
                                        if (res) {
                                                try {
                                                        System.out.println("==============");
                                                        TimeUnit.MINUTES.sleep(1);
                                                } finally {
                                                        lock.unlock();
                                                }
                                        }
                                }catch (Exception e){
                                        e.printStackTrace();
                                }finally {
                                        lock.unlock();
                                }
                        });
                }
        }

        public void asyncLock(){
                RLock lock = redisson.getLock("myLock");

                //RFuture<Void> lockFuture = lock.lockAsync();

                // or acquire lock and automatically unlock it after 10 seconds
                //RFuture<Void> lockFuture = lock.lockAsync(10, TimeUnit.SECONDS);

                // or wait for lock aquisition up to 100 seconds
                // and automatically unlock it after 10 seconds
                RFuture<Boolean> lockFuture = lock.tryLockAsync(100, 10, TimeUnit.SECONDS);

                lockFuture.whenComplete((res, exception) -> {
                        //TODO do some thing
                        lock.unlockAsync();
                });
        }

        public static void main2(String[] args) throws InterruptedException {
                ExecutorService pool = Executors.newFixedThreadPool(1000,new ThreadFactoryBuilder().setNameFormat("抢锁-%d").get());
                CountDownLatch ct = new CountDownLatch(1000);
                for (int i = 0; i < 10; i++) {
                        pool.submit(()->{
                                RLock lock = redisson.getLock("myLock");
                                long start = System.currentTimeMillis();
                                String name = Thread.currentThread().getName();
                                System.out.println((System.currentTimeMillis()-start)+"\t"+name+"启动");
                                RFuture<Boolean> lockFuture = lock.tryLockAsync(30, 10, TimeUnit.SECONDS);
                                lockFuture.whenComplete((res, exception) -> {
                                        System.out.println((System.currentTimeMillis()-start)+"\t"+Thread.currentThread().getName()+"还锁");
                                        System.out.println(name+"   id:"+Thread.currentThread().getId());
                                        lock.unlockAsync();
                                });
                                System.out.println((System.currentTimeMillis()-start)+"\t"+name+"完成");
                                ct.countDown();
                        });
                }
                ct.await();
        }


        public void reactiveLock(){
                RedissonReactiveClient redisson = Redisson.createReactive();
                RLockReactive lock = redisson.getLock("myLock");
//                Mono<Void> lockMono = lock.lock();

                // or acquire lock and automatically unlock it after 10 seconds
//                Mono<Void> lockMono = lock.lock(10, TimeUnit.SECONDS);

                // or wait for lock aquisition up to 100 seconds
                // and automatically unlock it after 10 seconds
                Mono<Boolean> lockMono = lock.tryLock(100, 10, TimeUnit.SECONDS);

                lockMono.doOnNext(res -> {
                        // ...
                }).doFinally(finl->lock.unlock()).subscribe();
        }

        public void rxJavaLock(){
                RedissonRxClient redisson = Redisson.createRx();
                RLockRx lock = redisson.getLock("myLock");

//                Completable lockRes = lock.lock();

                // or acquire lock and automatically unlock it after 10 seconds
//                Completable lockRes = lock.lock(10, TimeUnit.SECONDS);

                // or wait for lock aquisition up to 100 seconds
                // and automatically unlock it after 10 seconds
                Single<Boolean> lockRes = lock.tryLock(100, 10, TimeUnit.SECONDS);

                lockRes.doOnSuccess(res -> {
                        // ...
                }).doFinally(()->lock.unlock()).subscribe();
        }
}
